﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Model
{
    /// <summary>
    /// Режим просмотра каледаря - неделя, месяц или день
    /// </summary>
    public enum CalendarViewType { Month, Week, Day };

    /// <summary>
    /// Тип расписания - неделя или повторяющийся интервал
    /// </summary>
    public enum ScheduleType { Week = 1, Period = 2 }

    /// <summary>
    /// Тип рабочего графика - расписание на период или исключение на день
    /// </summary>
    public enum WorkingHoursType { Period = 1, DayException = 2 }

    public interface IWorkingHours
    {
        DateTime? TimeStart { get; }
        DateTime? TimeEnd { get; }
        DateTime? BreakStart { get; }
        DateTime? BreakEnd { get; }

        Schedule Schedule { get; }
        SchedulePeriod SchedulePeriod { get; }

        WorkingHoursType Type { get; }
        int EditId { get; }
        string Interval { get; }

        bool IsWorkingTime(int h, int m);
    }

    partial class Schedule
    {
        public IWorkingHours GetWorkingHours(DateTime date)
        {
            var exc = ScheduleDayExceptions.SingleOrDefault(sde => sde.Date.Date == date.Date && sde.Id > 0);
            if (exc != null) return exc;

            var period = GetPeriodByDate(date);
            if (period != null)
            {
                switch (period.TypeId)
                {
                    case (int)ScheduleType.Week:
                        return period.ScheduleDays.SingleOrDefault(d => d.Day == (int)date.DayOfWeek);
                    case (int)ScheduleType.Period:
                        int day = (date - period.DateStart).Days % period.ScheduleDays.Count();
                        return period.ScheduleDays.SingleOrDefault(d => d.Day == day);
                }
            }
            return null;
        }

        public DateTime GetEstimatedDate(DateTime date, int minutes)
        {
            int cnt = 0;
            while (minutes > 0)
            {
                DateTime cdate = date.AddDays(cnt);
                var wh = GetWorkingHours(cdate);
                if (wh.TimeStart.HasValue)
                {
                    //Установим датой начала либо переданную дату и время, либо время начала рабочего времени, если заявка создается раньше
                    var start = cnt == 0 && cdate.Hour > wh.TimeStart.Value.Hour ? new DateTime(wh.TimeStart.Value.Year, wh.TimeStart.Value.Month, wh.TimeStart.Value.Day, cdate.Hour, cdate.Minute, 0) : wh.TimeStart.Value;
                    TimeSpan? diff;
                    if (wh.BreakStart.HasValue && (cnt > 0 || wh.BreakStart.Value.Hour >= start.Hour)) 
                        diff = (wh.TimeEnd - start)- (wh.BreakEnd - (start > wh.BreakStart.Value ? start : wh.BreakStart));
                    else
                        diff = (wh.TimeEnd - start);
                    if (diff.HasValue && diff.Value.TotalMinutes > 0)
                    {
                        if (diff.Value.TotalMinutes >= minutes)
                        {
                            var estimatedDate = new DateTime(cdate.Year, cdate.Month, cdate.Day, start.Hour, start.Minute, 0).AddMinutes(minutes);
                            if(wh.BreakStart.HasValue && estimatedDate.Hour > wh.BreakStart.Value.Hour)
                                estimatedDate = estimatedDate.AddMinutes((int)(wh.BreakEnd-wh.BreakStart).Value.TotalMinutes);
                            return estimatedDate; 
                        }
                        else
                            minutes = minutes - (int)Math.Floor(diff.Value.TotalMinutes);
                    }
                }
                cnt++;
                //Если за год не получилось - скорее всего, какие-то косяки с расписанием. Просто прибавим минуты к стартовой дате.
                if (cnt >= 365) return date.AddMinutes(minutes);
            }
            return date.AddMinutes(minutes);
        }

        public SchedulePeriod GetPeriodByDate(DateTime date)
        {
            return SchedulePeriods.SingleOrDefault(s => s.DateStart.Date <= date && (!s.DateEnd.HasValue || s.DateEnd.Value >= date));
        }
    }

}
